package com.more.db.core;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.more.db.core.constant.DbProperty;
import com.more.db.core.model.DataSourceEnum;
import com.more.db.core.model.InitDataSourceModel;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.Map;
import java.util.Properties;

/**
 * springboot集成mybatis的基本入口 1）创建数据源(如果采用的是默认的tomcat-jdbc数据源，则不需要)
 * 2）创建SqlSessionFactory 3）配置事务管理器，除非需要使用事务，否则不用配置
 */
@Configuration // 该注解类似于spring配置文件
@MapperScan(basePackages = "com.more.db.*.mapper")
public class MyBatisConfig {

    // 精确到 master 目录，以便跟其他数据源隔离
    static final String PACKAGE = "com.more.db.*.model";
    static final String MAPPER_LOCATION = "classpath:mybatis-config.xml";

    @Autowired
    private Environment env;

    /**
     * 创建默认数据源
     */
    @Bean
    public DataSource consoleDataSource() throws Exception {
        Properties props = new Properties();
        props.put(DataSourceEnum.DRIVER_CLASS_NAME.getName(), env.getProperty(DbProperty.JDBC_DRIVER));
        props.put(DataSourceEnum.DB_URL.getName(), env.getProperty(DbProperty.JDBC_URL));
        props.put(DataSourceEnum.DB_USERNAME.getName(), env.getProperty(DbProperty.JDBC_USERNAME));
        props.put(DataSourceEnum.DB_PASSWORD.getName(), env.getProperty(DbProperty.JDBC_PASSWORD));
        return DruidDataSourceFactory.createDataSource(props);
    }

    /**
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候，默认选择哪一个，而不是让@autowire注解报错
     * @Qualifier 根据名称进行注入，通常是在具有相同的多个类型的实例的一个注入（例如有多个DataSource类型的实例）
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource(@Qualifier("consoleDataSource") DataSource consoleDataSource) {

        InitDataSourceModel model = InitDataSource.getInitDataSourceModel(consoleDataSource);
        Map<Object, Object> targetDataSources = InitDataSource.targetDataSources(model,
                env.getProperty(DbProperty.JDBC_DRIVER));
        targetDataSources.put(InitDataSource.DEFAULT_DB_NAME, consoleDataSource);
        DynamicDataSource dataSource = new DynamicDataSource();
        //DruidDataSource dataSource = new DruidDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(consoleDataSource);// 默认的datasource设置为consoleDataSource

        return dataSource;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(ds);// 指定数据源(这个必须有，否则报错)
        // 下边两句仅仅用于*.xml文件，如果整个持久层操作不需要使用到xml文件的话（只用注解就可以搞定），则不加
        factory.setTypeAliasesPackage(PACKAGE);// 指定基包
        factory.setConfigLocation(new ClassPathResource("/mybatis-config.xml"));
        /*fb.setMapperLocations(
                new PathMatchingResourcePatternResolver().
                        getResources(MAPPER_LOCATION));*/

        return factory.getObject();
    }

    /**
     * 配置事务管理器
     */
    @Bean
    public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
        return new DataSourceTransactionManager(dataSource);
    }



}